﻿using RockBus.BufferManager.Interfaces;
using RockBus.Configuration.Interfaces;
using RockBus.Logging.Interfaces;
using System.Reflection;

namespace RockBus.BufferManager
{
    public class WcfBufferManager : IBufferManager
    {
        private const int DefaultMaxPoolSize = 100;
        private const int DefaultMaxBufferSize = 32768;

        public WcfBufferManager(ILogger logger, IReadOnlyConfiguration configuration)
        {
            this.Logger = logger;
            this.Configuration = configuration;
            this.Configuration.OnChanged += Configuration_OnChanged;

            this.MaxPoolSize = DefaultMaxPoolSize;
            this.MaxBufferSize = DefaultMaxBufferSize;
            this.InternalBufferManager = System.ServiceModel.Channels.BufferManager.CreateBufferManager(this.Configuration.InternalConfiguration.BufferManagerMaxPoolSize, this.Configuration.InternalConfiguration.BufferManagerMaxBufferSize);
        }

        void Configuration_OnChanged(object sender, System.EventArgs e)
        {
            if ((this.MaxPoolSize != this.Configuration.InternalConfiguration.BufferManagerMaxPoolSize) ||
                (this.MaxBufferSize != this.Configuration.InternalConfiguration.BufferManagerMaxBufferSize))
            {
                this.MaxPoolSize = this.Configuration.InternalConfiguration.BufferManagerMaxPoolSize;
                this.MaxBufferSize = this.Configuration.InternalConfiguration.BufferManagerMaxBufferSize;
                this.InternalBufferManager = System.ServiceModel.Channels.BufferManager.CreateBufferManager(this.MaxPoolSize, this.MaxBufferSize);
            }
        }

        private ILogger Logger { get; set; }

        public IReadOnlyConfiguration Configuration { get; private set; }

        private int MaxPoolSize { get; set; }

        private int MaxBufferSize { get; set; }

        private System.ServiceModel.Channels.BufferManager InternalBufferManager { get; set; }

        public void Clear()
        {
            this.InternalBufferManager.Clear();
        }

        public void ReturnBuffer(byte[] buffer)
        {
            this.Logger.LogVerbose(MethodBase.GetCurrentMethod(), "Returning buffer with HashCode {0} and size {1}", buffer.GetHashCode(), buffer.Length);
            this.InternalBufferManager.ReturnBuffer(buffer);
        }

        public byte[] TakeBuffer(int bufferSize)
        {
            byte[] buffer = this.InternalBufferManager.TakeBuffer(bufferSize);
            this.Logger.LogVerbose(MethodBase.GetCurrentMethod(), "Taking buffer with HashCode {0} and size {1}", buffer.GetHashCode(), buffer.Length);
            return buffer;
        }
    }
}